home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************
- * flpcx.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
- *
- * Copyright (C) 1989,1990 by Michael Mauldin. Permission is granted
- * to use this file in whole or in part for any purpose, educational,
- * recreational or commercial, provided that this copyright notice
- * is retained unchanged. This software is available to all free of
- * charge by anonymous FTP and in the UUNET archives.
- *
- * flpcx.c:
- *
- * CONTENTS
- * write_pcx (image, stream)
- * read_pcx (image, stream, mstr, mlen)
- *
- * EDITLOG
- * LastEditDate = Mon Jun 25 00:17:11 1990 - Michael Mauldin
- * LastFileName = /usr2/mlm/src/misc/fbm/flpcx.c
- *
- * HISTORY
- * 25-Jun-90 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
- * Package for Release 1.0
- *
- * 03-Jan-90 Michael Mauldin (mlm) at Carnegie Mellon University
- * Added write_pcx, fixed bugs with read_pcx
- * Beta release (version 0.97) mlm@cs.cmu.edu
- *
- * 12-Nov-88 Michael Mauldin (mlm) at Carnegie-Mellon University
- * Created.
- *****************************************************************/
-
- # include <stdio.h>
- # include <math.h>
- # include <ctype.h>
- # include "fbm.h"
-
- /****************************************************************
- * pcx.h: Paintbrush file format header, as per "ZSoft Technical
- * Reference Manual for Publisher's Paintbrush, PC Paintbrush Plus,
- * PC Paintbrush and Frieze Graphics.", 1988, ZSoft corporation,
- *
- * 450 Franklin Rd. Suite 100 / Marietta, GA 30067 / 404-428-0008
- *
- * HISTORY
- * {1} 1-Sep-87 Michael L. Mauldin (mlm) at cognac
- * Created.
- *
- ****************************************************************/
-
- # define UBYTE unsigned char /* 8 bits unsigned */
- # define WORD short /* 16 bits signed */
-
- typedef struct pcxstruct {
- UBYTE Manufacturer; /* 10 == ZSoft PCX */
- UBYTE Version; /* Version Information */
- /* 0 == ver 2.5 */
- /* 2 == ver 2.8 w/pallete */
- /* 3 == 2.8 w/o pallete */
- /* 5 == ver 3.0 w/pallete */
- UBYTE Encoding; /* 01 == PCX run-length encoding */
- UBYTE BitsPerPixel; /* 8/number of pixels per byte */
- WORD Window[4]; /* xmin, ymin, xmax, ymax */
- WORD Hres; /* Horizontal resolution */
- WORD Vres; /* Vertical resolution */
- UBYTE Colormap[16][3]; /* Color Pallete, RGB in 0..255 */
- UBYTE Reserved; /* Reserved */
- UBYTE NPlanes; /* Number of Color Planes */
- WORD BytesPerLine; /* Number of bytes per scan line */
- WORD Palette; /* 1 = color/BW, 2 = grayscale */
- UBYTE Filler[58]; /* Pad header to 128 bytes */
- } PCXHDR;
-
- # define XMIN 0
- # define YMIN 1
- # define XMAX 2
- # define YMAX 3
-
- # define CNTMSK 0xc0
- # define MAXCNT 0x3f
-
- # define swapword(X) ((((X)&0xff) << 8) | (((X) & 0xff00) >> 8))
-
- /****************************************************************
- * write_pcx: Write PC Paintbrush format
- ****************************************************************/
-
- #ifndef lint
- static char *fbmid =
- "$FBM flpcx.c <1.0> 25-Jun-90 (C) 1989,1990 by Michael Mauldin, source \
- code available free from MLM@CS.CMU.EDU and from UUNET archives$";
- #endif
-
- write_pcx (image, stream)
- FBM *image;
- FILE *stream;
- { register unsigned char *line = NULL, *bmp;
- register int r, c, i, word, width, height;
- int rowlen;
- PCXHDR phdr;
-
- width = image->hdr.cols;
- height = image->hdr.rows;
-
- if (image->hdr.bits != 1)
- { fprintf (stderr, "write_pcx: can't handle %d bits per pixel\n", image->hdr.bits);
- return (0);
- }
-
- if (image->hdr.physbits != 8)
- { fprintf (stderr, "write_pcx: can't handle %d bits per pixel\n", image->hdr.physbits);
- return (0);
- }
-
- rowlen = (width + 7) / 8;
- line = (unsigned char *) malloc ((unsigned) rowlen);
-
- /* Initialize the PCX header */
- phdr.Manufacturer = 10; /* 10 == ZSoft PCX */
- phdr.Version = 3; /* ver 2.8 with pallette */
- phdr.Encoding = 1; /* 1 == PCX run-length encoding */
- phdr.BitsPerPixel = 1; /* 8/number of pixels per byte */
- phdr.Window[0] = 1; /* xmin */
- phdr.Window[1] = 1; /* ymin */
- phdr.Window[2] = width; /* xmax */
- phdr.Window[3] = height; /* ymax */
- phdr.Hres = 300; /* Horizontal resolution (300 dpi) */
- phdr.Vres = 300 * image->hdr.aspect; /* Vertical resolution */
-
- /* Clear out the color map */
- for (c=0; c<16; c++)
- for (r=0; r<3; r++)
- phdr.Colormap[c][r] = 0;
-
- phdr.Reserved = 0; /* Reserved */
- phdr.NPlanes = 1; /* Number of Color Planes */
- phdr.BytesPerLine = rowlen; /* Number of bytes per scan line */
- phdr.Palette = 0; /* 0=bw, 1=color, 2==grey */
-
- /* Clear filler */
- for (c=0; c<58; c++) phdr.Filler[c] = 0;
-
- /* PCX uses Little Indian byte order, swap on SUNS, RTs, ... */
- if (machine_byte_order () == BIG)
- { phdr.Window[0] = swapword (phdr.Window[0]);
- phdr.Window[1] = swapword (phdr.Window[1]);
- phdr.Window[2] = swapword (phdr.Window[2]);
- phdr.Window[3] = swapword (phdr.Window[3]);
- phdr.Hres = swapword (phdr.Hres);
- phdr.Vres = swapword (phdr.Vres);
- phdr.BytesPerLine = swapword (phdr.BytesPerLine);
- phdr.Palette = swapword (phdr.Palette);
- }
-
- /* Write out header */
- fwrite ((char *) &phdr, sizeof (phdr), 1, stream);
-
- /* For each scan line */
- for (r=0; r<height; r++)
- {
- /* bmp points to scan line in memory in FBM format */
- bmp = &(image->bm[r * image->hdr.rowlen]);
-
- /* Pack bits into a row of 8 bits per byte, then call writepcxrow */
- for (i=0; i<rowlen; i++)
- { word = 0;
- for (c=0; c<8; c++)
- { word <<= 1;
- word |= *bmp++ ? 1 : 0;
- }
- line[i] = word;
- }
-
- writepcxrow (line, rowlen, stream);
- }
-
- free ((char *) line);
- return (1);
- }
-
-
- /****************************************************************
- * Writepcxrow
- ****************************************************************/
-
- # define CNTMSK 0xc0
- # define MAXCNT 0x3f
-
- writepcxrow (row, len, stream)
- UBYTE *row;
- FILE *stream;
- { register int cnt, byte;
-
- cnt=1;
- byte = *row++;
- len--;
-
- while (len > 0 || cnt > 0)
- { if (len > 0 && cnt < MAXCNT && *row == byte)
- { cnt++; row++; len--; }
- else
- { if (cnt > 1 || (byte & CNTMSK) == CNTMSK)
- { fputc (CNTMSK | cnt, stream);
- fputc (byte, stream);
- }
- else if (cnt == 1)
- { fputc (byte, stream); }
-
- cnt=0;
-
- if (len > 0)
- { byte = *row++; cnt++; len--; }
- }
- }
- }
-
- /****************************************************************
- * read_pcx: Read PC Paintbrush format
- ****************************************************************/
-
- read_pcx (image, rfile, mstr, mlen)
- FBM *image;
- FILE *rfile;
- char *mstr;
- int mlen;
- { PCXHDR phdr;
- char *hp;
- register unsigned char *bmp;
- register int k, r, c, bit, byte, mask, width, height, rowlen;
- int depth, ptype, color, enc, clrlen, totalbytes;
- unsigned char *buf, *tail;
-
- /* Read PCX file header */
- hp = (char *) &phdr;
-
- if (mlen > 0) strncpy (hp, mstr, mlen);
-
- if (! fread ((char *) hp+mlen, sizeof (phdr) - mlen, 1, rfile))
- { perror ("read_fbm (header)"); return (0); }
-
- if (phdr.Manufacturer != PCX_MAGIC)
- { fprintf (stderr,
- "Error, file is not a PCX file, magic %02x is not 0a\n",
- phdr.Manufacturer);
- return (0);
- }
-
- /* PCX uses Little Indian byte order, swap on SUNS, RTs, ... */
- if (machine_byte_order () == BIG)
- { phdr.Window[0] = swapword (phdr.Window[0]);
- phdr.Window[1] = swapword (phdr.Window[1]);
- phdr.Window[2] = swapword (phdr.Window[2]);
- phdr.Window[3] = swapword (phdr.Window[3]);
- phdr.Hres = swapword (phdr.Hres);
- phdr.Vres = swapword (phdr.Vres);
- phdr.BytesPerLine = swapword (phdr.BytesPerLine);
- phdr.Palette = swapword (phdr.Palette);
- }
-
- # ifdef DEBUG
- fprintf (stderr, "Manufacturer %d\n", phdr.Manufacturer);
- fprintf (stderr, "Version %d\n", phdr.Version);
- fprintf (stderr, "Encoding %d\n", phdr.Encoding);
- fprintf (stderr, "BitsPerPixel %d\n", phdr.BitsPerPixel);
- fprintf (stderr, "Window0 %d\n", phdr.Window[0]);
- fprintf (stderr, "Window1 %d\n", phdr.Window[1]);
- fprintf (stderr, "Window2 %d\n", phdr.Window[2]);
- fprintf (stderr, "Window3 %d\n", phdr.Window[3]);
- fprintf (stderr, "Hres %d\n", phdr.Hres);
- fprintf (stderr, "Vres %d\n", phdr.Vres);
- fprintf (stderr, "Reserved %d\n", phdr.Reserved);
- fprintf (stderr, "NPlanes %d\n", phdr.NPlanes);
- fprintf (stderr, "BytesPerLine %d\n", phdr.BytesPerLine);
- fprintf (stderr, "Palette %d\n", phdr.Palette);
- # endif
-
- /* Now extract relevant features of PCX file header */
- width = phdr.Window[XMAX] - phdr.Window[XMIN] + 1;
- height = phdr.Window[YMAX] - phdr.Window[YMIN] + 1;
- depth = phdr.NPlanes;
- ptype = phdr.Version;
- color = ((ptype == 2) || (ptype == 5)) &&
- phdr.NPlanes > 1 &&
- phdr.Palette != 2;
- enc = phdr.Encoding;
-
- if (phdr.BitsPerPixel != 1)
- { fprintf (stderr, "%s %d bits per pixel with %d planes\n",
- "Error in PCX file, can't handle",
- phdr.BitsPerPixel, depth);
- return (0);
- }
-
- /* Initialize image header */
- image->hdr.cols = width;
- image->hdr.rows = height;
- image->hdr.planes = 1;
- image->hdr.bits = (color || depth > 1) ? 8 : 1;
- image->hdr.physbits = 8;
- image->hdr.rowlen = rowlen = 16 * ((width + 15) / 16);
- image->hdr.plnlen = rowlen * height;
- image->hdr.clrlen = clrlen = color ? (16 * 3) : 0;
- image->hdr.aspect = 1.0;
- image->hdr.title[0] = '\0';
- image->hdr.credits[0] = '\0';
-
- /* Describe what we are doing */
- fprintf (stderr, "Reading PCX file [%dx%d]", width, height);
- if (phdr.BitsPerPixel > 1)
- fprintf (stderr, ", %d bits per pixel", phdr.BitsPerPixel);
- if (depth > 1)
- fprintf (stderr, ", %d planes", depth);
- if (clrlen > 0)
- fprintf (stderr, ", %d colors", clrlen/3);
- fprintf (stderr, "\n");
-
- /* Allocate space */
- alloc_fbm (image);
-
- /* Read colormap if need be */
- if (clrlen > 0)
- { fprintf (stderr, "reading %d (really 16) colors\n", clrlen / 3);
-
- for (c=0; c<16; c++)
- { image->cm[c] = phdr.Colormap[c][0];
- image->cm[c+16] = phdr.Colormap[c][1];
- image->cm[c+32] = phdr.Colormap[c][2];
- }
- }
-
- /* Zero out the bits */
- bmp = image->bm;
- tail = bmp + image->hdr.plnlen;
-
- while (bmp < tail) { *bmp++ = 0; }
-
- /* Bytes per scan line */
- totalbytes = depth * phdr.BytesPerLine;
- buf = (unsigned char *) malloc ((unsigned) totalbytes);
-
- /* Now read bits */
- for (r=0; r<height; r++)
- { bmp = &(image->bm[r * rowlen]);
-
- /* Read a scan line */
- if (pcxline_read (enc, buf, totalbytes, rfile) == 0)
- { fprintf (stderr, "Premature EOF in row %d, totalbytes %d\n",
- r, totalbytes);
- free ((char *) buf);
- return (1);
- }
-
- # ifdef MONDO_DEBUG
- if (r == 211)
- { register int col = 0;
-
- fprintf (stderr, "Row %d, %d bytes:", r, totalbytes);
- for (c=0; c<totalbytes; c++)
- { if (col%32 == 0 || c%(width/8) == 0) { fprintf (stderr, "\n%3d:", c); col = 0; }
- if (col++ %8 == 0) fprintf (stderr, " ");
- fprintf (stderr, "%02x", buf[c]);
- }
- fprintf (stderr, "\n");
-
- col = 0;
- for (c=0; c<width; c++)
- { byte = c/8;
- mask = 0x80 >> (c%8);
- bit = ((buf[byte ] & mask) ? 1 : 0) |
- ((buf[byte+(width/8) ] & mask) ? 2 : 0) |
- ((buf[byte+2*(width/8)] & mask) ? 4 : 0) |
- ((buf[byte+3*(width/8)] & mask) ? 8 : 0);
- if (col%50 == 0) { fprintf (stderr, "\n%3d:", c); col=0; }
- if (col++%10 == 0) { fprintf (stderr, " ", c); }
- fprintf (stderr, "%1x", bit);
- }
- fprintf (stderr, "\n");
- }
- # endif
-
- /* Decode scan line into row of image */
- if (depth == 1)
- { bmp = &(image->bm[r * rowlen]);
-
- for (c=0; c<width; c++)
- { byte = c>>3;
- mask = 0x80 >> (c&7);
- *bmp++ = (buf[byte] & mask) ? WHITE : BLACK;
- }
- }
- else
- { for (k=0; k<depth; k++)
- { bmp = &(image->bm[r * rowlen]);
- bit = 1 << k;
-
-
- for (c=0; c<width; c++)
- { byte = ((c + k*width)>>3);
- mask = 0x80 >> (c&7);
-
- *bmp++ |= (buf[byte] & mask) ? bit : 0;
- }
- }
- }
- }
-
- if (depth > 1)
- { fprintf (stderr, "Read %d planes successfully\n", depth); }
-
- free ((char *) buf);
-
- return (1);
- }
-
- /****************************************************************
- * encget (pbyt, pcnt, fid) Page 10 of ZSoft Manual
- ****************************************************************/
-
- encget (pbyt, pcnt, fid)
- int *pbyt; /* Where to place data */
- int *pcnt; /* Where to place count */
- FILE *fid; /* Image file stream */
- { register int i;
-
- *pcnt = 1; /* Safety play */
- if (EOF == (i = getc (fid))) return (EOF);
- if (CNTMSK == (CNTMSK & i))
- { *pcnt = MAXCNT & i;
- if (EOF == (i = getc (fid))) return (EOF);
- }
- *pbyt = i;
- return (0);
- }
-
- /****************************************************************
- * pcxline_read
- ****************************************************************/
- pcxline_read (enc, buf, total, fid)
- unsigned char *buf; /* Output buffer */
- int total; /* Bytes in one scan line */
- FILE *fid; /* Input stream */
- { int data, count, len=0;
-
- if (enc != 1)
- { return (fread ((char *) buf, 1, total, fid)); }
-
- while (len < total)
- { if (EOF == encget (&data, &count, fid))
- return (len);
- while (count > 0) { *buf++ = data; len++; count--; }
- }
-
- if (count > 0)
- { fprintf (stderr, "%s, after %d bytes, lost %d bytes of %02x\n",
- "Error in reading scan lines", total, count, data);
- }
-
- return (len);
- }
-